package com.ezlcp.form.controller;

import com.ezlcp.commons.base.db.BaseService;
import com.ezlcp.commons.base.entity.IUser;
import com.ezlcp.commons.base.entity.JsonResult;
import com.ezlcp.commons.constant.Constants;
import com.ezlcp.commons.model.FileModel;
import com.ezlcp.commons.tool.IdGenerator;
import com.ezlcp.commons.tool.StringUtils;
import com.ezlcp.commons.utils.ContextUtil;
import com.ezlcp.commons.utils.FileUtil;
import com.ezlcp.commons.utils.ImageUtil;
import com.ezlcp.commons.utils.RequestUtil;
import com.ezlcp.form.entity.SysFile;
import com.ezlcp.form.service.FileServiceImpl;
import com.ezlcp.form.service.LogService;
import com.ezlcp.form.web.BaseController;
import com.ezlcp.form.web.file.FileOperator;
import com.ezlcp.form.web.file.IFileOperator;
import com.ezlcp.form.web.file.SysFileUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.mime.MimeType;
import org.apache.tika.mime.MimeTypes;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/ezlcp/form/file")
@Tag(name = "文件或附件接口")
public class FileController extends BaseController<SysFile> {
    /**
     * 缩略图宽度
     */
    private static final int THUMBNAIL_WIDTH = 300;
    /**
     * 缩略图高度
     */
    private static final int THUMBNAIL_HEIGHT = 300;
    @Resource
    FileServiceImpl fileService;

    @Resource
    LogService logService;

    @Resource
    private FileOperator fileOperator;

    @Operation(summary = "a.根据文件id查询文件")
    @GetMapping("/getByFileId")
    public Object getByFileId(@Parameter(description = "文件ID") @RequestParam(value = "fileId") String fileId) {
        return fileService.get(fileId);
    }

    @Operation(summary = "b.多个文件上传", description = "注意请求头Content-Type为multipart/form-data")
    @PostMapping("/upload")
    public JsonResult upload(MultipartHttpServletRequest request) throws Exception {
        JsonResult jsonResult = new JsonResult();
        String timestamp = request.getParameter("time");
        Map<String, MultipartFile> multiFileMap = request.getFileMap();
        Collection<MultipartFile> files = multiFileMap.values();
        Iterator<MultipartFile> it = files.iterator();
        List<SysFile> fileList = new ArrayList<>();
        //循环处理每个文件
        while (it.hasNext()) {
            String fileId = IdGenerator.getIdStr();
            SysFile file = new SysFile();
            file.setId(fileId);
            MultipartFile multipartFile = it.next();
            String oriFileName = multipartFile.getOriginalFilename();
            String contentType = multipartFile.getContentType();
            String[] split = contentType.split("/");
            String type = split[0];
            String extName = FileUtil.getFileExt(oriFileName);
            // 新文件名
            String newFileName = fileId + "." + extName;
            InputStream is = multipartFile.getInputStream();
            byte[] bytes = FileUtil.input2byte(is);
            FileModel fileModel = fileOperator.createFile(newFileName, bytes);
            file.setPath(fileModel.getRelPath());
            file.setFileName(oriFileName);
            file.setTotalBytes((long) bytes.length);
            file.setExtName(extName);
            file.setStatus(Constants.SHORT1);
            file.setMediaType(contentType);
            IUser curUser = ContextUtil.getCurrentUser();
            if (curUser != null) {
                file.setRemark(curUser.getFullName());
            }
            // 如果为图片，则生成图片的缩略图
            if ("image".equals(type) || isImage(extName)) {
                handImage(extName, bytes, fileOperator, file, fileModel.getRelPath());
            }
            fileService.save(file);
            file.setTimestamp(timestamp);
            fileList.add(file);
            file.setFileContent(bytes);
        }
        jsonResult.setSuccess(true);
        for (SysFile file : fileList) {
            file.setFileContent(null);
        }
        jsonResult.setData(fileList);
        jsonResult.setMessage("sysFile.uploadSuccess");
        jsonResult.setShow(false);
        return jsonResult;
    }

    /***
     * @description: 生成图片缩略图
     * @param extName 扩展名
     * @param bytes 文件内容
     * @param operator 操作类
     * @param file 文件实体
     * @param relPath 路径
     * @author Elwin ZHANG
     * @date 2022/5/16 13:08
     */
    private void handImage(String extName, byte[] bytes, IFileOperator operator, SysFile file, String relPath) {
        String fileId = IdGenerator.getIdStr();
        String imgName = fileId + "." + extName;
        byte[] imgBytes = ImageUtil.thumbnailImage(bytes, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, extName);
        if (imgBytes == null) {
            file.setThumbnail(relPath);
        } else {
            FileModel imgModel = operator.createFile(imgName, imgBytes);
            String thumbnailPath = imgModel.getRelPath();
            file.setThumbnail(thumbnailPath);
        }
    }

    @Operation(summary = "c.文件下载或打开")
    @GetMapping("download/{fileId}")
    public void downloadOne(@Parameter(description = "文件ID") @PathVariable("fileId") String fileId) throws Exception {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        download(response, fileId, false);
        //写日志
        logService.saveSystemLog(getComment(), "download", fileId, "");
    }

    @Operation(summary = "d.缩略图下载")
    @GetMapping("downloadScale/{fileId}")
    public void downloadScale(@Parameter(description = "文件ID") @PathVariable("fileId") String fileId) throws Exception {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        download(response, fileId, true);
        //写日志
        logService.saveSystemLog(getComment(), "download", fileId, "");
    }

    /**
     * 下载文件
     *
     * @param response
     * @param fileId   文件ID
     * @param isScale  是否缩略图
     */
    private void download(HttpServletResponse response, String fileId, boolean isScale) {
        var sysFile = (SysFile) fileService.get(fileId);
        fileOperator.downFile(response, sysFile, isScale, true);
    }

    @Operation(summary = "i.获取附件或图片路径")
    @GetMapping("getFilePath")
    public JsonResult getFilePath(@Parameter(description = "系统文件ID") @RequestParam(value = "fileId") String fileId,
                                  @Parameter(description = "是否取缩略图") @RequestParam(value = "isScale") boolean isScale) throws Exception {
        JsonResult result = JsonResult.Fail("sysFile.gainError");
        var sysFile = fileService.get(fileId);
        String path = SysFileUtil.getFilePath(sysFile, isScale);
        result.setSuccess(true);
        result.setMessage(path);
        result.setData(path);
        return result;
    }

    /**
     * 文件预览
     *
     * @param fileId
     */
    @Operation(summary = "e.文件预览")
    @GetMapping("previewFile")
    public void previewFile(@Parameter(description = "系统文件ID") @RequestParam String fileId) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        var sysFile = fileService.get(fileId);
        fileOperator.downFile(response, sysFile, false, false);
        //写日志
        logService.saveSystemLog(getComment(), "preview file", fileId, "");
    }

    /**
     * 图片预览
     *
     * @param request
     * @param response
     */
    @Operation(summary = "f.图片预览")
    @GetMapping("previewImg")
    public void previewImg(HttpServletRequest request, HttpServletResponse response) {
        String fileId = request.getParameter("fileId");
        boolean isScale = RequestUtil.getBoolean(request, "isScale", false);
        var sysFile = fileService.get(fileId);
        fileOperator.downFile(response, sysFile, isScale, false);
        //写日志
        logService.saveSystemLog(getComment(), "preview image", fileId, "");
    }

    /**
     * 根据文件的后缀名判断是否为图片
     *
     * @param extName 扩展名
     */
    private boolean isImage(String extName) {
        if (StringUtils.isEmpty(extName)) {
            return false;
        }
        extName = extName.toLowerCase();
        return "jpg".equals(extName) || "jpeg".equals(extName) || "png".equals(extName)
                || "gif".equals(extName) || "bmp".equals(extName);
    }


    @Operation(summary = "g.网络图片上传", description = "网络图片，输入参数为网址")
    @PostMapping("uploadPicture")
    public String uploadPicture(@Parameter(description = "图片网址") @RequestParam(value = "urlStr") String urlStr) throws Exception {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //设置超时间为3秒
        conn.setConnectTimeout(3 * 1000);
        InputStream inputStream = conn.getInputStream();
        String contentType = conn.getContentType();
        String fileId = IdGenerator.getIdStr();
        SysFile file = new SysFile();
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[2048];
        int len = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        inputStream.close();
        byte[] bytes = outStream.toByteArray();
        MimeTypes allTypes = MimeTypes.getDefaultMimeTypes();
        MimeType jpeg = allTypes.forName(contentType);
        String extName = jpeg.getExtension();
        if (StringUtils.isNotEmpty(extName)) {
            extName = extName.substring(1);
        }
        //生成缩略图
        String fileName = fileId + "." + extName;
        FileModel fileModel = fileOperator.createFile(fileName, bytes);
        if (isImage(extName)) {
            byte[] imgBytes = ImageUtil.thumbnailImage(bytes, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, extName);
            fileName = IdGenerator.getIdStr() + "." + extName;
            FileModel imgModel = fileOperator.createFile(fileName, imgBytes);
            String thumbnailPath = imgModel.getRelPath();
            file.setThumbnail(thumbnailPath);
        }
        file.setId(fileId);
        file.setPath(fileModel.getRelPath());
        file.setFileName(fileName);
        IUser curUser = ContextUtil.getCurrentUser();
        if (curUser != null) {
            file.setRemark(curUser.getFullName());
        }
        file.setExtName(extName);
        file.setStatus(Constants.SHORT1);
        fileService.save(file);
        return fileId;
    }

    /**
     * 下载文件（将文件打成压缩包）
     *
     * @param fileIdStr 逗号隔开
     * @throws Exception
     */
    @Operation(summary = "h.下载多个文件", description = "将多个文件压缩成zip文件再下载")
    @GetMapping("downloadZip/{fileIdStr}")
    public void downloadZip(@Parameter(description = "多个文件ID，用逗号分隔") @PathVariable("fileIdStr") String fileIdStr) throws Exception {
        if (StringUtils.isNotEmpty(fileIdStr)) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletResponse response = attributes.getResponse();
            String[] fileIds = fileIdStr.split(",");
            List<File> fileList = new ArrayList<>();
            String path = SysFileUtil.getUploadPath();
            for (int i = 0; i < fileIds.length; i++) {
                var sysFile = fileService.get(fileIds[i]);
                if (StringUtils.isNotEmpty(sysFile.getPath())) {
                    fileList.add(new File(path + sysFile.getPath()));
                }
            }
            String fileName = IdGenerator.getIdStr() + ".zip";
            FileUtil.compressedDownload(response, fileList, path, fileName);
            //写日志
            logService.saveSystemLog(getComment(), "download zip", null, fileIdStr);
        }
    }

    @Override
    public BaseService getBaseService() {
        return fileService;
    }

    @Override
    public String getComment() {
        return "文件管理";
    }
}